import pandas as pd
import re
from typing import List

from interfaces.transformers import IFailureList
from interfaces.data_loader import IDataLoader
from interfaces.form_metadata import IFormMetadataProvider
from constants import SUBJECT_NUMBER, DATA_FESTIVAL, MERGE_KEYS, FormAllConstants


class FailureListTransformer(IFailureList):
    def __init__(self, data_loader: IDataLoader, metadata: IFormMetadataProvider):
        self.data_loader = data_loader
        self.metadata = metadata

    def get_failure_list(self) -> pd.DataFrame:
        result_ModuleOIDIsICF = self.metadata.get_targets((FormAllConstants.IsICF, True), FormAllConstants.ModuleOID, True)
        result_FolderNameIsICF = self.metadata.get_targets((FormAllConstants.IsICF, True), FormAllConstants.FolderName, True)
        result_ModuleOIDIsReview = self.metadata.get_targets((FormAllConstants.IsReview, True), FormAllConstants.ModuleOID, True)
        result_FolderNameIsReview = self.metadata.get_targets((FormAllConstants.IsReview, True), FormAllConstants.FolderName, True)

        icf_data = self._get_failure_data(result_ModuleOIDIsICF, result_FolderNameIsICF, 'IsICF')
        review_data = self._get_failure_data(result_ModuleOIDIsReview, result_FolderNameIsReview, 'IsReview')

        if not icf_data.empty and not review_data.empty:
            common_merge_keys = [key for key in MERGE_KEYS if key in icf_data.columns and key in review_data.columns]
            if common_merge_keys:
                combined_data = pd.merge(icf_data, review_data, on=common_merge_keys, how='outer', suffixes=('_ICF', '_Review'))
            else:
                combined_data = pd.concat([icf_data, review_data], axis=1)
        elif not icf_data.empty:
            combined_data = icf_data
        else:
            combined_data = review_data

        if not combined_data.empty and SUBJECT_NUMBER in combined_data.columns:
            combined_data = combined_data.drop_duplicates(subset=[SUBJECT_NUMBER], keep='last')
        return combined_data

    def _get_failure_data(self, module_oids: List[str], folder_names: List[str], data_type: str) -> pd.DataFrame:
        failure_data = pd.DataFrame()
        if not module_oids or not folder_names:
            return failure_data
        for module_oid in module_oids:
            if data_type == 'IsReview':
                full_df = self.data_loader.load_sheet(module_oid)
                reas_columns = [col for col in full_df.columns if re.match(r'.*REAS$', col)]
                if not reas_columns:
                    continue
                columns_to_extract = [SUBJECT_NUMBER, DATA_FESTIVAL] + reas_columns
            else:
                columns_to_extract = [SUBJECT_NUMBER, '受试者状态', 'DSSTDAT', DATA_FESTIVAL]
            df = self.data_loader.load_specific(module_oid, columns_to_extract)
            for folder_name in folder_names:
                filtered_df = df[df[DATA_FESTIVAL] == folder_name].copy()
                if not filtered_df.empty:
                    data_columns = [col for col in columns_to_extract if col != DATA_FESTIVAL]
                    available_columns = [col for col in data_columns if col in filtered_df.columns]
                    current_data = filtered_df[available_columns].copy()
                    current_data = current_data.rename(columns=lambda col: f"{module_oid}_{col}" if col not in MERGE_KEYS else col)
                    failure_data = pd.concat([failure_data, current_data], ignore_index=True)
        return failure_data